﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using LPTask.Interfaces.Presenters;
using LPTask.Interfaces.Views;
using SimplexSolver;

namespace LPTask.Presenters
{
    internal class GeneralPresenter : IGeneralPresenter
    {
        private readonly IGeneralView _generalView;

        private readonly IUserMessageView _userMessageView;

        private readonly SolverComposition _solverComposition;

        private readonly BackgroundWorker _backgroundWorker;

        public void Activate()
        {
            try
            {
                _generalView.ShowView();
            }
            catch (Exception ex)
            {
                _userMessageView.ShowError(ex);
            }
        }

        public ReadOnlyCollection<ITaskPresenter> TaskPresenters
        {
            get { return _taskPresenters; }
            set
            {
                _taskPresenters = value;
                UpdateViewList();
            }
        }

        private ReadOnlyCollection<ITaskPresenter> _taskPresenters;

        public IResultPresenter ResultPresenter { get; set; }

        public GeneralPresenter(IGeneralView generalView)
        {
            _solverComposition = new SolverComposition();
            _backgroundWorker = new BackgroundWorker();
            _backgroundWorker.DoWork += BackgroundWorker_DoWork;
            _backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
            _solverComposition.MessageTransferNeeded += SolverComposition_MessageTransferNeeded;
            _generalView = generalView;
            _userMessageView = _generalView.UserMessageView;
            _generalView.SolveTaskNeeded += GeneralView_SolveTaskNeeded;
            _generalView.ActiveTaskChangeNeeded += GeneralView_ActiveTaskChangeNeeded;
        }

        private void UpdateViewList()
        {
            IEnumerable<string> taskNames = _taskPresenters.Select(taskPresenter => taskPresenter.Name);
            _generalView.SetTaskNames(taskNames.ToList());
            if (_taskPresenters.Count > 0)
            {
                ITaskView activeView = _taskPresenters[0].TaskView;
                _generalView.SetActiveTaskView(activeView);
            }
        }

        private void GeneralView_ActiveTaskChangeNeeded(object sender, EventArgs e)
        {
            ITaskPresenter selectedPresenter = GetSelectedPresenter();
            ITaskView activeView = selectedPresenter.TaskView;
            _generalView.SetActiveTaskView(activeView);
        }

        private ITaskPresenter GetSelectedPresenter()
        {
            string taskName = _generalView.SelectedTaskName;
            return _taskPresenters.FirstOrDefault(taskPresenter => taskPresenter.Name == taskName);
        }

        private void GeneralView_SolveTaskNeeded(object sender, EventArgs e)
        {
            ITaskPresenter selectedPresenter = GetSelectedPresenter();
            selectedPresenter.TaskView.Enabled = false;
            ILPTask task = selectedPresenter.GetTask();
            _backgroundWorker.RunWorkerAsync(task);
        }

        private void SolverComposition_MessageTransferNeeded(object sender, MessageTransferNeededEventArgs e)
        {
            MessageTransferNeededEventArgs.EMessageType type = e.MessageType;
            string message = e.Message;
            switch (type)
            {
                case MessageTransferNeededEventArgs.EMessageType.Information:
                    _userMessageView.ShowInfo(message);
                    break;
                case MessageTransferNeededEventArgs.EMessageType.Warning:
                    _userMessageView.ShowWarning(message);
                    break;
                case MessageTransferNeededEventArgs.EMessageType.Error:
                    _userMessageView.ShowError(message);
                    break;
                default:
                    var ex = new ArgumentOutOfRangeException("Неверный тип сообщения!");
                    _userMessageView.ShowError(ex);
                    break;
            }
        }

        private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var task = (ILPTask) e.Argument;
            ISolution solution = _solverComposition.SolveScalar(task);
            e.Result = solution;
        }

        private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var solution = (ISolution) e.Result;
            ResultPresenter.SetResult(solution);
            ITaskPresenter selectedPresenter = GetSelectedPresenter();
            selectedPresenter.TaskView.Enabled = true;
        }
    }
}